共计 4641 个字符,预计需要花费 12 分钟才能阅读完成。
一. 分页器简介
当数据量非常大时, 我们不可能把所有的数据都放在同一页中, 于是就有了分页的概念, 将数据像书一样每一页规定可容纳多少条数据, 运用到 Django 中的分页组件, 它其实是 Django 内置的一个类
二.Paginator 对象与 Page 类对象
1. 如何得到这两个类对象
- 导入分页类
from django.core.paginator import Paginator
- Paginator 类对象
# 语法伪代码
paginator = Paginator([要分页的数据],[每页显示条数])
# 示例
paginator = Paginator(shop_list,10)
- Page 类对象
# 语法伪代码
page = paginator.page([第几页])
# 示例
page = paginator.page(2) # 获取第二页对象
2.Paginator 类对象属性和方法
- 属性
属性名 | 说明 |
---|---|
count | 返回数据总条数 |
num_pages | 返回分页之后的总页数 |
per_page | 每页显示的条数 |
page_range | 返回分页后页码的列表 |
- 方法
方法名 | 说明 |
---|---|
page(self, number) | 返回地 number 页的 page 类实例对象 |
3.Page 类对象属性和方法
- 属性
属性名 | 说明 |
---|---|
number | 返回当前页页码 |
object_list | 返回当前页的数据列表 |
paginator | 返回对应的 Paginator 类对象 |
- 方法
方法名 | 说明 |
---|---|
has_previous() | 判断当前页是否有上一页 |
has_next() | 判断当前页是否有下一页 |
previous_page_number() | 返回前一页页码 |
next_page_number() | 返回下一页页码 |
三. 创建表并插入数据(准备工作)
1. 创建模型类
class Shop(models.Model):
name = models.CharField(max_length=64)
price = models.DecimalField(max_digits=8,decimal_places=2)
nums = models.IntegerField(verbose_name='商品剩余')
def __str__(self):
return self.name
2. 使用 for 循环批量插入数据
for i in range(1,151):
models.Shop.objects.create(name=f'商品{i}',price=10+int(f'{i}'),nums=f'{random.randint(1,15)}')
每循环一次就连接一次数据库, 效率低
3.bulk_create() : 批量插入数据
import random
shop_list = []
for i in range(1,151):
book = models.Shop(name=f'商品{i}',price=10+int(f'{i}'),nums=f'{random.randint(1,15)}')
shop_list.append(book)
models.Shop.objects.bulk_create(shop_list,10) # 第二个参数是每次插入的条数
可以指定每次插入的条数, 效率高
4. 将初始数据渲染到页面
- page_shop.html 文件
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-info">
<div class="panel-heading text-center"> 商品信息表 </div>
<div class="panel-body">
<table class="table table-striped table-hover">
<thead>
<tr>
<th> 编号 </th>
<th> 商品名 </th>
<th> 价格 </th>
<th> 剩余个数 </th>
</tr>
</thead>
<tbody>
{% for obj in shop_obj %}
<tr>
<th>{{obj.id}}</th>
<th>{{obj.name}}</th>
<th>{{obj.price}}</th>
<th>{{obj.nums}}</th>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
- 展示效果
以上是没有没有分页的效果, 一页翻不到头, 使用起来不方便
四. 分页器完整用法
1. 实现需求
- 每页显示 15 条数据
- 页码列表只展示 11 页, 随着当前页变化
- 当前页为第一页则禁用 ''上一页'' 按钮
- 当前页为最后页则禁用 ''下一页'' 按钮
- 当前页按钮处于激活状态
2. 效果展示
- 整体展示
- 分页按钮展示
3. 代码实现
- 路由层 urls.py 文件
re_path('^page_shop/', views.page_shop)
- 视图层 views.py 文件
视图层需要传给前端使用的三个参数(核心):
- 分页后的 paginator 对象, 用来展示数据
- 分页后的页码列表, 我们规定每次展示 11 个页码, 中间页码为当前页, 左右页码随之变化(这里需要注意前 11 页和后 11 页)
- 收到前端点击的页码, 我们要返回该页码 (page) 对象(注意小于或超出中页码的情况)
from django.shortcuts import render, HttpResponse, redirect
from app01 import models
def page_shop(request):
# 🔰1. 分页后的 paginator 对象
current_page = int(request.GET.get('page_num',1)) # 获取用户点击的页码, 没有则默认第一页
shop_list = models.Shop.objects.all() # 获取所有的商品对象列表
paginator = Paginator(shop_list,15) # 每页展示 15 条商品信息
# 🔰2. 页码列表
# 如果分页后的总页数大于 11
if paginator.num_pages > 11:
# 总共 11 页, 取中间页 (当前页) 来判断是否是第 1~11 页
if current_page - 5 < 1:
# 1~11 页码列表
page_range = range(1, 12)
# 取 11 页的中间页 (当前页) 判断是否是最后 11 页
elif current_page + 5 > paginator.num_pages:
# 最后 11 页页码列表
page_range = range(paginator.num_pages - 10, paginator.num_pages + 1)
else:
# 如果不是前面 11 页, 也不是后面 11 页, 那么页码列表动态就会随着当前列表动态加减
page_range = range(current_page - 5, current_page + 5)
else:
# 总页数小于 11 就直接全部显示
page_range = paginator.page_range
# 🔰3.page 对象
try:
# 如果前端传过来的页码小于分页后的最小页码或者大于最大页码就会报错
page = paginator.page(current_page)
except Exception as E:
current_page = 1 # 如果超出或小于我们就让其默认展示第一页
page = paginator.page(current_page)
return render(request, 'page.html', {'page_range': page_range, 'page': page, 'current_page': current_page})
- 模板层 page.html 文件
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-info">
<div class="panel-heading text-center"> 商品信息表 </div>
<div class="panel-body">
<table class="table table-striped table-hover">
<thead>
<tr>
<th> 编号 </th>
<th> 商品名 </th>
<th> 价格 </th>
<th> 剩余个数 </th>
</tr>
</thead>
<tbody>
{# 展示当前页的所有数据 #}
{% for obj in page.object_list %}
<tr>
<th>{{obj.id}}</th>
<th>{{obj.name}}</th>
<th>{{obj.price}}</th>
<th>{{obj.nums}}</th>
</tr>
{% endfor %}
</tbody>
</table>
{# ------------------- 上面为数据渲染, 下面为页码列表 -------------------- #}
<div class="text-center">
<nav aria-label="Page navigation">
<ul class="pagination">
{# 判断当前页是否有上一页(针对向左的箭头按钮) #}
{% if page.has_previous %}
<li>
{# 如果有上一页就跳到上一页 #}
<a href="/page_shop/?page_num={{page.previous_page_number}}"
aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
{# 如果没有上一页, 就将该按钮禁用 #}
<li class="disabled">
<a href="" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{# 从页码列表中循环取出页码与当前页做对比 #}
{% for foo in page_range %}
{% if current_page == foo %}
{# 如果是当前页, 就将当前页按钮变成激活状态(蓝色) #}
<li class="active"><a href="/page_shop/?page_num={{foo}}">{{foo}}</a></li>
{% else %}
{# 如果不是则不变色 #}
<li><a href="/page_shop/?page_num={{foo}}">{{foo}}</a></li>
{% endif %}
{% endfor %}
{# 判断但前页是否有下一页(针对向右的箭头按钮) #}
{% if page.has_next %}
<li>
{# 如果有则跳转到下一页 #}
<a href="/page_shop/?page_num={{page.next_page_number}}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
{# 没有下一页则将按钮禁用 #}
<li class="disabled">
<a href="" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
</div>
以上视图层和模板层可以当固定模板来使用, 只需要修改模型类(你的数据)
正文完